package com.hontech.kaltaapp.utils

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.view.View
import com.hontech.kaltaapp.exception.AckTimeoutException
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.Runnable
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import kotlinx.serialization.json.Json
import org.greenrobot.eventbus.EventBus

private class HandlerThread2(name: String) : HandlerThread(name) {

    init {
        start()
    }
}

object ConnTask : Handler(HandlerThread2("conn-task").looper)
object AppTask : Handler(Looper.getMainLooper())
private val bus = EventBus.builder().logNoSubscriberMessages(false).build()

fun register(any: Any) {
    if (!bus.isRegistered(any)) {
        bus.register(any)
    }
}

fun unregister(any: Any) {
    if (bus.isRegistered(any)) {
        bus.unregister(any)
    }
}

fun postEvent(event: Any) {
    bus.post(event)
}

val defJson = Json {
    encodeDefaults = true
    ignoreUnknownKeys = true
}

suspend fun <T> CompletableDeferred<T>.await(timeout: Long): T {

    try {
        return withTimeout(timeout) { await() }
    } catch (e: TimeoutCancellationException) {
        throw AckTimeoutException("ACK或者返回超时")
    }
}

private val uiScope = CoroutineScope(Dispatchers.Main + Job())



fun runOnUi(cb: suspend (CoroutineScope) -> Unit) {
    uiScope.launch { cb(this) }
}

private var lastClickTimestamp = 0L

fun View.onClick(cb: suspend (CoroutineScope) -> Unit) {
    this.setOnClickListener {
        val last = lastClickTimestamp
        val now = System.currentTimeMillis()
        if (now < (last + 500)) {
            return@setOnClickListener
        }
        lastClickTimestamp = now
        runOnUi(cb)
    }
}

private class PromiseTask<T>(val cb: ()->T) : Runnable {

    private val promise = CompletableDeferred<T>()

    suspend fun await() = promise.await()

    override fun run() {
        try {
            val r = cb()
            promise.complete(r)
        } catch (e: Exception) {
            promise.completeExceptionally(e)
        }
    }
}


suspend fun<T> runAsync(cb: ()->T): T {
    val task = PromiseTask(cb)
    ConnTask.post(task)
    return task.await()
}



